package com.xms.sdk.client;

import cn.hutool.core.lang.Assert;
import com.xms.core.data.Entity;
import com.xms.core.enums.AccessRightValue;
import com.xms.core.exception.XmsException;
import com.xms.core.model.PagedList;
import com.xms.sdk.core.RetrieverParameter;
import com.xms.sdk.core.query.*;
import com.xms.sdk.data.IOrganizationDataRetriever;
import com.xms.sdk.service.IDataFinder;
import com.xms.utils.CollectionUtil;
import com.xms.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 * DataFinder
 * </p>
 *
 * @author migo
 * @since 2021/9/6
 */
@Service
public class DataFinder extends DataProviderBase implements IDataFinder {
    private IOrganizationDataRetriever _organizationDataRetriever;

    @Autowired
    public void DataFinder(IOrganizationDataRetriever organizationDataRetriever) {
        _organizationDataRetriever = organizationDataRetriever;
    }

    private RetrieverParameter buildParameters(QueryBase request, boolean ignorePermissions) throws XmsException {
        RetrieverParameter parameters = RetrieverParameter.build(request, _currentUser).setIgnorePermissions(ignorePermissions);
        if (!ignorePermissions) {
            //get entity permissions
            parameters.setEntityPermissions(getUserEntityPermissions(request, AccessRightValue.Read));
        }
        return parameters;
    }

    @Override
    public Entity retrieve(QueryBase request, boolean ignorePermissions) throws Exception {
        verifyQuery(request);

        return _organizationDataRetriever.getOne(buildParameters(request, ignorePermissions)).data;
    }

    @Override
    public List<Entity> retrieveAll(QueryBase request, boolean ignorePermissions) throws XmsException, SQLException {
        verifyQuery(request);

        return _organizationDataRetriever.list(buildParameters(request, ignorePermissions)).data;
    }

    @Override
    public PagedList<Entity> retrieveMultiple(QueryBase request, boolean ignorePermissions) throws Exception {
        verifyQuery(request);

        return _organizationDataRetriever.paged(buildParameters(request, ignorePermissions)).data;
    }

    @Override
    public Entity retrieve(QueryBase request) throws Exception {
        return this.retrieve(request, false);
    }

    @Override
    public Entity retrieveById(String entityName, UUID id, String primarykey, boolean ignorePermissions) throws Exception {
        QueryExpression q = new QueryExpression(entityName);
        q.ColumnSet.AllColumns = true;
        q.Criteria.addCondition(primarykey.isEmpty() ? entityName + "id" : primarykey, ConditionOperator.Equal, id);

        return this.retrieve(q, ignorePermissions);
    }

    @Override
    public Entity retrieveById(String entityName, UUID id, String primarykey) throws Exception {
        return this.retrieveById(entityName, id, primarykey, false);
    }

    @Override
    public Entity retrieveById(String entityName, UUID id, boolean ignorePermissions) throws Exception {
        return this.retrieveById(entityName, id, "", false);
    }

    @Override
    public Entity retrieveById(String entityName, UUID id) throws Exception {
        return this.retrieveById(entityName, id, false);
    }

    @Override
    public Entity retrieveByAttribute(String entityName, HashMap<String, Object> key_value, List<String> columns, boolean ignorePermissions) throws Exception {
        Assert.notEmpty(key_value);
        QueryExpression q = new QueryExpression(entityName);
        if (CollectionUtil.isEmpty(columns)) {
            q.ColumnSet.AllColumns = true;
        } else {
            q.ColumnSet.addColumns(columns);
        }
        for (Map.Entry<String, Object> item : key_value.entrySet()) {
            q.Criteria.addCondition(item.getKey(), ConditionOperator.Equal, item.getValue());
        }

        return this.retrieve(q, ignorePermissions);
    }

    @Override
    public Entity retrieveByAttribute(String entityName, HashMap<String, Object> key_value, List<String> columns) throws Exception {
        return this.retrieveByAttribute(entityName, key_value, columns, false);
    }

    @Override
    public Entity retrieveByAttribute(String entityName, HashMap<String, Object> key_value) throws Exception {
        return this.retrieveByAttribute(entityName, key_value, null, false);
    }

    @Override
    public List<Entity> retrieveMultipleByAttribute(String entityName, HashMap<String, Object> key_value) throws Exception {
        Assert.notEmpty(key_value);
        QueryExpression q = new QueryExpression(entityName);
        q.ColumnSet.AllColumns = true;
        for (Map.Entry<String, Object> item : key_value.entrySet()) {
            q.Criteria.addCondition(item.getKey(), ConditionOperator.Equal, item.getValue());
        }
        return this.retrieveAll(q, false);
    }

    @Override
    public List<Entity> retrieveAll(QueryBase request) throws XmsException, SQLException {
        return this.retrieveAll(request, false);
    }

    @Override
    public List<Entity> retrieveAll(String entityName, List<String> columns, OrderExpression order, boolean ignorePermissions) throws XmsException, SQLException {
        QueryExpression q = new QueryExpression(entityName);
        if (CollectionUtil.notEmpty(columns)) {
            q.ColumnSet.addColumns(columns);
        } else {
            q.ColumnSet.AllColumns = true;
        }
        if (order != null) {
            q.AddOrder(order.AttributeName, order.OrderType);
        }

        return this.retrieveAll(q, ignorePermissions);
    }

    @Override
    public List<Entity> retrieveAll(String entityName, List<String> columns, OrderExpression order) throws XmsException, SQLException {
        return this.retrieveAll(entityName, columns, order, false);
    }

    @Override
    public List<Entity> retrieveAll(String entityName, List<String> columns) throws XmsException, SQLException {
        return this.retrieveAll(entityName, columns, null, false);
    }

    @Override
    public List<Entity> retrieveAll(String entityName) throws XmsException, SQLException {
        return this.retrieveAll(entityName, null, null, false);
    }

    @Override
    public PagedList<Entity> retrieveMultiple(QueryBase request) throws Exception {
        return this.retrieveMultiple(request, false);
    }

    private void verifyQuery(QueryBase query) throws XmsException {
        ColumnSet columnSet = null;
        String entityName = null;
        if (query instanceof QueryExpression) {
            com.xms.sdk.core.query.QueryExpression queryExpression = (QueryExpression) query;
            columnSet = queryExpression.ColumnSet;
            entityName = queryExpression.EntityName;
        } else if (query instanceof QueryByAttribute) {
            com.xms.sdk.core.query.QueryByAttribute queryByAttribute = (QueryByAttribute) query;
            columnSet = queryByAttribute.ColumnSet;
            entityName = queryByAttribute.EntityName;
        }
        if (columnSet == null || (!columnSet.AllColumns && CollectionUtil.isEmpty(columnSet.Columns))) {
            onException("没有指定要查询所有字段时，请提供要查询的字段名");
        }
        if (StringUtil.isEmpty(entityName)) {
            onException("没有指定要查询的实体名称");
        }
    }
}
